package com.dap.utils;

import java.io.InputStream;
import java.util.*;

import com.dap.api.ISunriseService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationContextException;
import org.springframework.core.io.Resource;

/**
 * 用于动态引用dubbo服务,相当于标签 dubbo:reference
 */
public class LocalServiceContainer implements ApplicationContextAware {
    private static final Logger logger = LoggerFactory.getLogger(LocalServiceContainer.class);

    private static ApplicationContext applicationContext;   // Spring应用上下文环境

    private final static HashMap<String, ISunriseService> sunriseReferenceMap = new HashMap<>();
    private final static HashMap<Class<?>, HashMap<String, Object>> otherReferenceMap = new HashMap<>();


    private final Resource[] serviceMapConfigResources;
    private LocalServiceContainer(Resource[] serviceMapConfigResources) {
        this.serviceMapConfigResources = serviceMapConfigResources;
    }


    
    public static <T> T getReference(String serviceGroup, Class<T> interfaceClass) {
        if (ISunriseService.class.equals(interfaceClass)) {
            return (T) getSunriseReference(serviceGroup);
        } else {
            HashMap<String, Object> serviceGroupBeanMap = otherReferenceMap.get(interfaceClass);
            if (null == serviceGroupBeanMap) {
                return null;
            } else {
                return (T) serviceGroupBeanMap.get(serviceGroup);
            }
        }
    }

    public static ISunriseService getSunriseReference(String serviceGroup) {
        // 包含符号. 说明是根据组名 获取服务
        if (serviceGroup.indexOf('.') >= 0) {
            ISunriseService result = sunriseReferenceMap.get(serviceGroup);
            if (null != result)
                return result;
        }

        return (ISunriseService) LocalServiceContainer.applicationContext.getBean(serviceGroup);
    }
    public static ISunriseService getSunriseReference(String serviceGroup, String version) {
        if (StringUtils.isEmpty(version)) {
            return getSunriseReference(serviceGroup);
        }

        // 包含符号. 说明是根据组名 获取服务
        if (serviceGroup.indexOf('.') >= 0) {
            ISunriseService result = sunriseReferenceMap.get(serviceGroup+"&"+version);
            if (null != result)
                return result;
        }

        return getSunriseReference(serviceGroup);
    }

    public static ISunriseService getSunriseReferenceNotByServiceName(String serviceGroup) {
        return sunriseReferenceMap.get(serviceGroup);
    }
    public static ISunriseService getSunriseReferenceNotByServiceName(String serviceGroup, String version) {
        if (StringUtils.isEmpty(version)) {
            return getSunriseReferenceNotByServiceName(serviceGroup);
        }

        ISunriseService result = sunriseReferenceMap.get(serviceGroup+"&"+version);
        if (null != result) {
            return result;
        }

        return getSunriseReferenceNotByServiceName(serviceGroup);
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        LocalServiceContainer.applicationContext = applicationContext;
        try {
            for (Resource serviceMapConfigResource : this.serviceMapConfigResources) {
                loadReferenceMap(applicationContext, serviceMapConfigResource);
            }

            if (logger.isDebugEnabled()) {
                StringBuilder sb = new StringBuilder();
                for (String key : sunriseReferenceMap.keySet()) {
                    sb.append(key).append('\n');
                }
                logger.debug("sunriseReferenceMap groups :\n{}", sb.toString());
            }
        } catch (Exception e) {
            logger.warn("", e);
            throw new ApplicationContextException("", e);
        }
    }


    /**
     * 默认配置格式为:
     * group,class=serviceName
     * 比如:
     * pay.service,com.sbp.pay.trade.PayProvider=payProviderImpl
     *
     * 如果配置的接口是 com.dap.api.ISunriseService, 配置格式为:
     * group=serviceName,class
     * 比如:
     * base.pay.updateTradeAmount=tradeUpdateAmountServiceImpl
     * */
    private static void loadReferenceMap(ApplicationContext applicationContext, Resource serviceMapConfigFilePath) throws Exception {
        InputStream inputStream = serviceMapConfigFilePath.getInputStream();
        Properties properties = new Properties();
        properties.load(inputStream);
        inputStream.close();

        for (Map.Entry<Object,Object> entry : properties.entrySet()) {
            String key = (String) entry.getKey();
            String serviceName = ((String) entry.getValue()).trim();

            String serviceGroup;
            Class<?> interfaceClass;
            int commIdx = key.indexOf(',');
            if (commIdx >= 0) {
                serviceGroup = key.substring(0, commIdx);
                interfaceClass = Class.forName(key.substring(commIdx+1));
            } else {
                serviceGroup = key;
                interfaceClass = ISunriseService.class;
            }

            Object service;
            try {
                service = applicationContext.getBean(serviceName);
                if (null == service || !interfaceClass.isInstance(service))
                    throw new Exception();
            } catch (Exception e) {
                logger.warn("file={}, config[{}={}], service not exists or invalid", serviceMapConfigFilePath.getFilename(), key, serviceName);
                throw e;
            }

            if (ISunriseService.class.equals(interfaceClass)) {
                sunriseReferenceMap.put(serviceGroup, (ISunriseService) service);
            } else {
                HashMap<String, Object> serviceGroupBeanMap = otherReferenceMap.get(interfaceClass);
                if (null == serviceGroupBeanMap) {
                    serviceGroupBeanMap = new HashMap<>();
                    otherReferenceMap.put(interfaceClass, serviceGroupBeanMap);
                }
                serviceGroupBeanMap.put(serviceGroup, service);
            }
        }
    }
}
